package dbsync4j.mapper.concrete.diff;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import dbsync4j.core.behavior.DatabaseObject;
import dbsync4j.core.concrete.ConcreteColumnAttribute;
import dbsync4j.mapper.behavior.diff.Difference;
import dbsync4j.mapper.behavior.diff.DifferenceType;

public class AttributeValueDifference extends AbstractDifference implements Difference {

	private Map<String,Field> ownFields;
	private Map<String,Field> childFields;
	
	public AttributeValueDifference(DatabaseObject source,
			DatabaseObject destiny, String attribute, String tag) {
		
		super(source, destiny, tag);
		this.attribute = attribute;

		loadFields();
	}

	private void loadFields() {
		
		ownFields = new HashMap<String, Field>();
		childFields = new HashMap<String, Field>();
		Collection<Class<?>> classes = new ArrayList<Class<?>>(); 
		
		Class<?> klass = this.source.getClass();
		classes.add(klass);
		
		while(klass != null && !klass.equals(Object.class)) {
			klass = klass.getSuperclass();
			classes.add(klass);
		}
		
		for(Class<?> k : classes) {
			
			Field[] array_fields = k.getDeclaredFields();
			
			for(Field f : array_fields) {
				f.setAccessible(true);
				ownFields.put(f.getName(), f);
				
				if(f.getName().equals("columnAttributes")) {
					
					Field[] declaredFields = ConcreteColumnAttribute.class.getDeclaredFields();
					
					for(Field field : declaredFields) {
						field.setAccessible(true);
						childFields.put(field.getName(), field);
					}
				}
			}
		}
	}
	
	@Override
	public String getDifference() {
		
		String result = this.rb.getString("msg02");
		this.difference = result;
		
		return result;
	}

	@Override
	public DifferenceType getDifferenceType() {
		
		throw new NotImplementedException();
	}

	/* (non-Javadoc)
	 * @see dbsync4j.mapper.behavior.diff.Difference#getDestinyValue()
	 */
	@Override
	public String getDestinyValue() {

		return getAttributeValue(this.destiny);	
	}

	/* (non-Javadoc)
	 * @see dbsync4j.mapper.behavior.diff.Difference#getSourceValue()
	 */
	@Override
	public String getSourceValue() {
		
		return getAttributeValue(this.source);
	}

	private String getAttributeValue(Object databaseObject) {

		String result = this.rb.getString("msg01");
		
		try {
			
			Field field = ownFields.get(attribute);
			
			if(field == null) {
				
				field = childFields.get(attribute.replace("columnAttributes.", ""));
				Field columnAttributes = ownFields.get("columnAttributes");				
				
				return String.valueOf(field.get(columnAttributes.get(databaseObject)));	
			} else {
				return String.valueOf(field.get(databaseObject));	
			}
			
		} catch (IllegalArgumentException e) {

			e.printStackTrace();
			return result;
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
			return result;
		}		
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		
		StringBuffer buffer = new StringBuffer(super.toString());
		buffer.append("\n" + this.rb.getString("atributte") + ": " + this.rb.getString(attribute.replace("columnAttributes.", "")));
		buffer.append("\n" + this.rb.getString("values") + ": " + this.rb.getString("source") + " - " + getSourceValue() + ", " + this.rb.getString("destiny") + " - " + getDestinyValue());
		
		return buffer.toString();
	}
	
}
